Loc - Lua Objective-C


Loc Library provides a bridge of type conversion between Lua and Objective-C. It handles type conversion and function reflection, hence we can simply reqeust Objective-C property, call Objective-C function in Lua with Lua syntax.

Values of types listed below are copied to the corresponding types on conversion in each direction. For userdata type, Loc will register metatable for the relative Objective-C type to reflect Lua methods to instance methods.

Objective-C type Lua type
nil nil
NSNull nil
NSString string
NSNumber number, boolean
NSDictionary table, userdata
NSArray table, userdata
NSObject userdata
Class userdata

Syntax and Usage

Regiester Loc

If we want to use Loc in project, we just call following method to register Loc Library to lua_State:

loc_registerlib(L);

Now we are good to play Objective-C in Lua.

Push object to Lua stack

Loc extends NSObject with - (BOOL)pushToLuaState:(lua_State *)L via Category, so we can call this function to push object to stack of given lua_State

[obj pushToLuaState:L];

If obj is nil, it pushes nothing to stack, which may causes problem, so it is recommended to call following method to push object, if object may be nil:

loc_pushid(L, obj);

The reset process is the same as working with other type (e.g.: string, number, boolean) which is pushed to stack. We can set value to global with void lua_setglobal (lua_State *L, const char *var), or call a Lua function with the object as arguments.

Fetch object from Lua stack

Loc provides similar "to" method as lua_tostring, lua_tonumber in Lua, to fetch object from Lua stack:

id loc_toid(lua_State *L, int idx)

The method automatically returns associated NSObject instance base on above table.

If we want to gurantee the value is not primitive, which must be Objetive-C object, we could use similar "check" method:

id loc_checkuserdata(lua_State *L, int idx);
id loc_checkclass(lua_State *L, int idx, Class clazz);

NSString *loc_checkstring(lua_State *L, int idx);

We can also compulsorily convert Lua table to NSArray or NSDictionary:

NSArray *loc_toarray(lua_State *L, int idx);
NSDictionary *loc_todictionary(lua_State *L, int idx);

Get property value of object

When we want to get propety value of object, we can use colon(:) syntax, and give property name, and call it as function:

local name = obj:name();

dot(.) syntax does not work to access the property.

Set property value of object

We can pass new value to property function to set value on it with colon(:) syntax:

obj:name('newName');

We can also use dot(.) syntax to assign new value directly to property:

obj.name = 'newName';

Call method of object

Getting property is almost the same as call method of object if the method does not have argument. For methods with arguments, Objetive-C method seperate method name into multiple parts, and use colon(:) to delimit name and arguments. The method name use in Lua should be the concatenation of all parts, captalize the character right after colon, remove all colons.

For example, if we define a method in Objective-C like:

- (void)printBool:(BOOL)b string:(NSString *)s andArray:(NSArray *)a

In lua we call as:

obj:printBoolStringAndArray(true, 'Hello World', arrObj);

If method has return value, we can assign to variable, or pass it to other method as arguments

local sum = obj:addAWithB(21, 7);

ATTENTION: function call should use colon(:) syntax like getting property

NSDictionary & NSArray

Loc does some specialization for NSDictionary and NSArray, as they are Objective-C system collection, and used very often. Intead of use NSInvocation to reflect method call, Loc direct map methods.

Lua Syntax Mapped Call
dict:get(key) [dict objectForKey:key]
dict:set(key, value) [dict setObject:value forKey:key]
dict:haskey(key) [dict objectForKey:key] != nil
dict:remove(key) [dict removeObjectForKey:key]
dict:count() [dict count]
Lua Syntax Mapped Call
arr:get(index) [arr objectAtIndex:index-1]
arr:insert(index, value) [arr insertObject:value atIndex:index-1]
arr:add(value) [arr addObject:value]
arr:remove(index) [arr removeObjectAtIndex:index-1]
arr:count() [arr count]

To be the same convention as Lua, the index used Lua script is 1-based, and it automatically minus 1 in Objective-C to be 0-based.

Loc also provides totable() method for NSDictioanry and NSArray, it converts instance of NSDictioanry or NSArray to Lua table. However, it only convert one depth level, it does not recursively convert keys and values.

With totable(), we could use the result in pairs(t) or ipairs(t) to interate content in for loop.

for k,v in pairs(dict:totable()) do  
    -- iteration body
end

for i,v in ipairs(arr:totable()) do 
    -- iteration body 
end

Loc Lua Library

Loc provides some auxiliary methods to use in Lua script, all methods are in global loc table. The list below shows the methods we can use Lua:

We don't use loc.todictionary() very often, as Loc converts table to NSDictionary as default. But if some methods accept NSArray as arguemnts, we need to manually convert table to NSArray with loc.toarray(), then pass to method.

Tricky Usage

Call method of Class

Loc allows us to call Class method as well, but it limits to method with no arguments. So we could even construct a new object in Lua:

local clazz = loc.toclass('SomeClassName');
local obj = clazz:alloc():init();

It's totally work, but not recommended, because we really do not want Lua to handle Objective-C memory management.

The common usage is call some method to get singleton of a Class:

local obj = clazz:instance();

Loc is not able to call Class Methods with any argument yet.

Access property or method with variable

Lua is scripting language like PHP, Javascript. It can access value of table by variable, not just type in code. Loc support it as well, but not very well.

We can use brackts to access property on Objective-C object, and assign value to it:

local prop = 'name';
obj[prop] = 'newName';

But if we want to get value, we need to call as method, and pass object as first argument:

local name = obj[prop](obj);

local funcName = 'addAWithB';
obj[funcName](obj, 21, 7);

This is just how Lua dot(.) syntax work.


Supported by Ider